{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__init__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# \n",
    "# init in Card\n",
    "# \n",
    "class Card:\n",
    "    def __init__( self, rank, suit ):\n",
    "        self.suit = suit\n",
    "        self.rank = rank\n",
    "        self.hard, self.soft = self._points()\n",
    "\n",
    "class NumberCard( Card ):\n",
    "    def _points( self ):\n",
    "        return int( self.rank ), int( self.rank )\n",
    "    \n",
    "class AceCard( Card ):\n",
    "    def _points( self ):\n",
    "        return 1, 11\n",
    "    \n",
    "class FaceCard( Card ):\n",
    "    def _points( self ):\n",
    "        return 10, 10\n",
    "    \n",
    "class Suit:\n",
    "    def __init__( self, name, symbol ):\n",
    "        self.name = name\n",
    "        self.symbol = symbol\n",
    "        \n",
    "Club, Diamond, Heart, Spade = Suit( 'Club', '♣', ), Suit( \"Diamond\", '♦' ), Suit( 'Heart', '♥' ), Suit( 'Spade', '♠')\n",
    "\n",
    "cards = [ AceCard( 'A', Spade ), NumberCard( '2', Spade ), NumberCard( '3', Spade )]\n",
    "\n",
    "\n",
    "# factory function class return a different class\n",
    "def card( rank:str, suit ):\n",
    "    if rank == 1: return AceCard( 'A', suit )\n",
    "    elif 2 <= rank < 11: return NumberCard( str(rank), suit )\n",
    "    elif 11 <= rank < 14:\n",
    "        name = { 11: 'J', 12:'Q', 13: 'K'}[rank]\n",
    "        return FaceCard( name, suit )\n",
    "    else:\n",
    "        raise Exception( \"Rank out of range\" )\n",
    "    \n",
    "deck = [ card( rank, suit ) # create 52 cards by card factory function\n",
    "        for rank in range( 1, 14 ) \n",
    "            for suit in ( Club, Diamond, Heart, Spade )]\n",
    "\n",
    "def card4( rank:object, suit ):\n",
    "    class_ = { 1: AceCard, 11: FaceCard, 12: FaceCard, 13: FaceCard},get( rank, NumberCard )\n",
    "    return class_( rank, suit )\n",
    "\n",
    "    from functools import partial\n",
    "    part_class = {\n",
    "        1: partial(AceCard, 'A'),\n",
    "        11: partial(FaceCard, 'J'),\n",
    "        12: partial(FaceCard, 'Q'),\n",
    "        13: partial(FaceCard, 'K')\n",
    "    }.get( rank, partial(NumberCard, str(rank)))\n",
    "    return part_class( suit )\n",
    "\n",
    "# Card factory Smooth interface definition and must be called in order\n",
    "class CardFactory:\n",
    "    def rank( self, rank ):\n",
    "        self.class_, self.rank_str = {\n",
    "        1: partial(AceCard, 'A'),\n",
    "        11: partial(FaceCard, 'J'),\n",
    "        12: partial(FaceCard, 'Q'),\n",
    "        13: partial(FaceCard, 'K')\n",
    "    }.get( rank, (NumberCard, str(rank)))\n",
    "        return self\n",
    "    def suit( self, suit ):\n",
    "        return self.class_( self.rank_str, suit )\n",
    "card8 = CardFactory()\n",
    "deck8 = [ card8.rank(r+1).suits(s) for r in range(13) for s in (Club, Diamond, Heart, Spade)]\n",
    "\n",
    "\n",
    "# \n",
    "# init in Card child class\n",
    "# \n",
    "class Card:\n",
    "    pass\n",
    "class NumberCard( Card ):\n",
    "    def __init__( self, rank, suit ):\n",
    "        self.suit= suit\n",
    "        self.rank= str(rank)\n",
    "        self.hard = self.soft = rank\n",
    "class AceCard( Card ):\n",
    "    def __init__( self, rank, suit ):\n",
    "        self.suit= suit\n",
    "        self.rank= \"A\"\n",
    "        self.hard, self.soft = 1, 11\n",
    "class FaceCard( Card ):\n",
    "    def __init__( self, rank, suit ):\n",
    "        self.suit= suit\n",
    "        self.rank= {11: 'J', 12: 'Q', 13: 'K' }[rank]\n",
    "        self.hard = self.soft = 1\n",
    "\n",
    "class Card:\n",
    "    def __init__( self, rank, suit, hard, soft ):\n",
    "        self.rank= rankself.suit= suit\n",
    "        self.hard= hard\n",
    "        self.soft= soft\n",
    "class NumberCard( Card ):\n",
    "    def __init__( self, rank, suit ):\n",
    "        super().__init__( str(rank), suit, rank, rank )\n",
    "class AceCard( Card ):\n",
    "    def __init__( self, rank, suit ):\n",
    "        super().__init__( \"A\", suit, 1, 11 )\n",
    "class FaceCard( Card ):\n",
    "    def __init__( self, rank, suit ):\n",
    "        super().__init__( {11: 'J', 12: 'Q', 13: 'K' }[rank], suit, 10, 10 )\n",
    "    \n",
    "def card10( rank, suit ):\n",
    "    if rank == 1: return AceCard( rank, suit )\n",
    "    elif 2 <= rank < 11: return NumberCard( rank, suit )\n",
    "    elif 11 <= rank < 14: return FaceCard( rank, suit )\n",
    "    else:\n",
    "        raise Exception( \"Rank out of range\" )\n",
    "    \n",
    "# \n",
    "# Simple combination of objects\n",
    "# \n",
    "\n",
    "# Encapsulated collection class\n",
    "import random\n",
    "class Deck:\n",
    "    def __init__( self ):\n",
    "        self._cards = [ card6(r+1, s) for r in range(13) for s in (Club, Diamond, Heart, Spade)]\n",
    "        random.shuffle( self._cards)\n",
    "    def pop(self):\n",
    "        return self._cards.pop()\n",
    "d = Deck()\n",
    "hand = [ d.pop(), d.pop() ]\n",
    "\n",
    "# Extend the collecion class\n",
    "class Deck2(list):\n",
    "    def __init__( self ):\n",
    "        super().__init__(card6(r+1, s) for r in range(13) for s in (Club, Diamond, Heart, Spade))\n",
    "        random.shuffle(self)\n",
    "\n",
    "d = Deck()\n",
    "hand = [ d.pop(), d.pop() ]\n",
    "\n",
    "\n",
    "class Deck3(list):\n",
    "    def __init__(self, decks=1):\n",
    "        super().__init__()\n",
    "        for i in range(decks):\n",
    "            self.extend( card6(r+1,s) for r in range(13) for s in (Club, Diamond, Heart, Spade) )\n",
    "        random.shuffle( self )\n",
    "        burn= random.randint(1,52)\n",
    "        for i in range(burn): self.pop()\n",
    "        \n",
    "        \n",
    "# 对象：私有（实现）和公有（接口）函数或属性\n",
    "# python中的命名是根据函数（或属性）的目的来定义\n",
    "\n",
    "# \"{0!r}\".format()和\"{0!s}\".format()并不会调用 __format__()方法。它们会直接调用__repr__()或者__str__()。\n",
    "\n",
    "#  当Python遇到NotImplemented的值时，会尝试交换两个操作数的顺序"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__del__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Removing Noisy at 1965755738712\n"
     ]
    }
   ],
   "source": [
    "# 很难预测什么时候__del__()方法会被调用。它并不总是在使用del语句删除对象时被调用\n",
    "class Noisy:\n",
    "    def __del__(self):\n",
    "        print(f\"Removing {__class__.__name__} at {id(self)}\")\n",
    "\n",
    "x = Noisy()\n",
    "del x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Python没有响应del语句。这说明这些Noisy对象的引用计数器还没有归零\n",
    "ln = [ Noisy(), Noisy() ]\n",
    "ln2= ln[:]\n",
    "del ln"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Removing Noisy at 1965755814240\n",
      "Removing Noisy at 1965755814128\n"
     ]
    }
   ],
   "source": [
    "# 有两个列表引用了Noisy对象，所以在这两个列表被删除并且引用计数器归零之前，Python不会销毁这两个Noisy对象\n",
    "del ln2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1965756025488"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 循环引用和垃圾回收\n",
    "# 一个父类包含一个子类的集合，同时集合中的每个子类实例又包含父类的引用\n",
    "class Parent:\n",
    "    def __init__( self, *children ):\n",
    "        self.children= list(children)\n",
    "        for child in self.children:\n",
    "            child.parent= self\n",
    "    def __del__( self ):\n",
    "        print( \"Removing {__class__.__name__} {id:d}\".format( __class__=self.__class__, id=id(self)) )\n",
    "class Child:\n",
    "    def __del__( self ):\n",
    "        print( \"Removing {__class__.__name__} {id:d}\".format( __class__=self.__class__, id=id(self)) )\n",
    "        \n",
    "        \n",
    "p = Parent( Child(), Child() )\n",
    "id(p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Parent和它的两个初始Child实例都不能被删除，因为它们之间互相引用。\n",
    "del p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Removing Parent 1965755815192\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "1965755816592"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 创建一个没有Child集合的Parent实例\n",
    "p = Parent()\n",
    "id(p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Removing Parent 1965755816592\n"
     ]
    }
   ],
   "source": [
    "del p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "73"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 由于互相之间有引用存在，因此我们不能从内存中删除Parent实例和它包含的Child实例的集合\n",
    "# 导入垃圾回收器的接口——gc，我们就可以回收和显示这些不能被删除的对象\n",
    "# 使用了gc.collect()方法回收所有定义了__del__()方法但是无法被删除的对象\n",
    "import gc\n",
    "gc.collect()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gc.garbage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# __del__()方法是在循环引用被解除并且引用计数器已经归零之后被调用的。\n",
    "# 当有循环引用时，我们不能只是简单地依赖于Python中计算引用数量的机制来清理内存中的无用对象。\n",
    "# 我们必须显式地解除循环引用或者使用可以保证垃圾回收的weakref引用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 循环引用和weakref模块\n",
    "# 如果我们需要循环引用，但是又希望将清理资源的代码写在__del__()中，这时候我们可以使用弱引用。\n",
    "\n",
    "# 循环引用的一个常见场景是互相引用：一个父类中包含了一个集合，集合中的每一个实例也包含了一个指向父类的引用\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Removing Parent2 1965755815528\n",
      "Removing Child 1965755816928\n",
      "Removing Child 1965755815976\n"
     ]
    }
   ],
   "source": [
    "# 对一个对象的强引用就是直接引用\n",
    "class B:\n",
    "    pass\n",
    "\n",
    "b =B()\n",
    "\n",
    "# 要找个一个弱引用相关的对象需要两个步骤\n",
    "# 一个弱引用会调用x.parent()，这个函数将弱引用作为一个可调用对象来查找它真正的父对象。\n",
    "    # 这个过程让引用计数器得以归零，垃圾回收器可以回收引用的对象，但是不回收这个弱引用。\n",
    "# weakref定义了一系列使用了弱引用而没有使用强引用的集合\n",
    "\n",
    "# 可以修改Parent和Child类，在Child指向Parent的引用中使用弱引用，这样就可以简单地保证无用对象会被销毁\n",
    "import weakref\n",
    "class Parent2:\n",
    "    def __init__( self, *children ):\n",
    "        self.children= list(children)\n",
    "        for child in self.children:\n",
    "            child.parent= weakref.ref(self)\n",
    "    def __del__( self ):\n",
    "        print( \"Removing {__class__.__name__} {id:d}\".format(__class__= self.__class__, id=id(self)) )\n",
    "\n",
    "# 在Child类中，我们必须用上面说的两步操作来定位parent对象\n",
    "# p = self.parent()\n",
    "# if p is not None:\n",
    "#     pass\n",
    "#     # process p, the Parent instance\n",
    "# else:\n",
    "#     pass\n",
    "#     # the parent instance was garbage collected.\n",
    "\n",
    "# 当我们使用这个新的Parent2类时，可以看到引用计数成功地归零同时对象也被删除了\n",
    "p = Parent2( Child(), Child() )\n",
    "del p"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__new__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(6.5, 65.0, 'knots')"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# __new__()方法天生就是一个静态方法\n",
    "# 即使没有使用@staticmethod修饰符，它也是静态的\n",
    "# 它没有使用self变量，因为它的工作是创建最终会被赋值给self变量的对象\n",
    "\n",
    "# 使用的方法签名是__new__( cls, *args,**kw)。cls变量是准备创建的类实例\n",
    "class Float_Units( float ):\n",
    "    def __new__( cls, value, unit ):\n",
    "        obj= super().__new__( cls, value )  # create obj\n",
    "        obj.unit= unit\n",
    "        return obj\n",
    "speed= Float_Units( 6.5, \"knots\" )\n",
    "speed, speed * 10, speed.unit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 所有类的元类型都是type，type()函数被用来创建类对象\n",
    "\n",
    "# 元类型示例1——有序的属性\n",
    "    # 创建一个元类型。元类型的__prepare__()和__new__()方法会改变目标类创建的方式，会将原本的dict类替换为OrderedDict类\n",
    "        # __prepare__()方法会在类创建之前执行，它的工作是创建初始的命名空间对象，类定义最后被添加到这个对象中\n",
    "        # 这个方法可以用来处理任何在类的主体开始执行前需要的准备工作\n",
    "        \n",
    "        # __new__()静态方法在类的主体被加入命名空间后开始执行\n",
    "        # 它的参数是要创建的类对象、类名、基类的元组和创建好的命名空间匹配对象\n",
    "        # __new__()方法向类中增加了一个_order属性，用于存储原始的属性创建顺序\n",
    "        \n",
    "    # 创建一个基于此元类型的抽象基类\n",
    "    # 创建一个继承于这个抽象基类的子类\n",
    "import collections\n",
    "class Ordered_Attributes(type):\n",
    "    @classmethod\n",
    "    def __prepare__(metacls, name, bases, **kwds):\n",
    "        print(f\"metacls: {metacls}, name: {name}, bases: {bases}, kwds: {kwds}\\n\")\n",
    "        return collections.OrderedDict()  # namespace\n",
    "    def __new__(cls, name, bases, namespace, **kwds):\n",
    "        result = super().__new__(cls, name, bases, namespace)\n",
    "        result._order = tuple(n for n in namespace if not n.startswith('__'))\n",
    "        print(\"\\n\"\\\n",
    "            .join(f\"cls: {cls}, name: {name}, bases: {bases}, namespace: {namespace}, kwds: {kwds}, result.__name__: {result.__name__}, result: {result}, result_order: {result._order}\\n\".split(\",\")))\n",
    "        return result # class\n",
    "# 当我们定义新的抽象基类时，我们可以用这个元类型而非type\n",
    "class Order_Preserved( metaclass=Ordered_Attributes ):\n",
    "    pass\n",
    "\n",
    "# 将这个新的抽象基类作为任何其他自定义类的基类\n",
    "class Something( Order_Preserved ):\n",
    "    this= 'text'\n",
    "    def z( self ):\n",
    "        return False\n",
    "    b= 'order is preserved'\n",
    "    a= 'more text'\n",
    "\n",
    "Something._order"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 元类型示例2——自引用\n",
    "# 定义一个长度的标准单位。我们可以把任何其他单位转换为标准单位，也可以把标准单位转换为任何其他单位。\n",
    "# 可以很容易地将单位转换变成一致的两步操作，而不用再考虑包含了所有可能转换的复杂矩阵\n",
    "\n",
    "# 享元模式\n",
    "\n",
    "# 这个类的目的是Unit.value()可以将一个值从给定的单位转换为标准单位，\n",
    "# 而Unit.convert()方法可以将一个值从标准单位转换为给定的单位\n",
    "class Unit:\n",
    "    \"\"\"Full name for the unit.\"\"\"\n",
    "    factor= 1.0\n",
    "    standard= None # Reference to the appropriate StandardUnit\n",
    "    name= \"\" # Abbreviation of the unit's name.\n",
    "    @classmethod\n",
    "    def value( class_, value ):\n",
    "        if value is None: return None\n",
    "        return value/class_.factor\n",
    "    @classmethod\n",
    "    def convert( class_, value ):\n",
    "        if value is None: return None\n",
    "        return value*class_.factor\n",
    "\n",
    "# 定义一个可以向类定义中插入一个循环引用的元类型 new_class.standard = new_class\n",
    "class UnitMeta(type):\n",
    "    def __new__(cls, name, bases, dict):\n",
    "        new_class= super().__new__(cls, name, bases, dict)\n",
    "        new_class.standard = new_class\n",
    "        return new_class\n",
    "    \n",
    "class Standard_Unit( Unit, metaclass=UnitMeta ):\n",
    "    pass\n",
    "\n",
    "# INCH定为标准单位\n",
    "class INCH( Standard_Unit ):\n",
    "    \"\"\"Inches\"\"\"\n",
    "    name= \"in\"\n",
    "    \n",
    "class FOOT( Unit ):\n",
    "    \"\"\"Feet\"\"\"\n",
    "    name= \"ft\"\n",
    "    standard= INCH\n",
    "    factor= 1/12\n",
    "    \n",
    "class CENTIMETER( Unit ):\n",
    "    \"\"\"Centimeters\"\"\"\n",
    "    name= \"cm\"\n",
    "    standard= INCH\n",
    "    factor= 2.54\n",
    "    \n",
    "class METER( Unit ):\n",
    "    \"\"\"Meters\"\"\"\n",
    "    name= \"m\"\n",
    "    standard= INCH\n",
    "    factor= .0254\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (<ipython-input-6-f9c5ee9fe5f9>, line 7)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;36m  File \u001b[1;32m\"<ipython-input-6-f9c5ee9fe5f9>\"\u001b[1;36m, line \u001b[1;32m7\u001b[0m\n\u001b[1;33m    In [9]: class C(dict):\u001b[0m\n\u001b[1;37m                ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "# __getattr__()函数可以用来做两件事。\n",
    "# 首先，如果属性已经被赋值，__getattr__()则不会被调用，直接返回属性值即可。\n",
    "# 其次，如果属性没有被赋值，那么将使用__getattr__()函数的返回值。\n",
    "# 如果找不到相关属性，要记得抛出AttributeError异常。\n",
    "\n",
    "\n",
    "In [9]: class C(dict):\n",
    "   ...:     def __init__(self, a, b):\n",
    "   ...:         self.a = a\n",
    "   ...:         self.b= b\n",
    "            # __setattr__()函数\n",
    "            # 可使用self['distance']方式，就可有效地避免__setattr__()函数的递归调用\n",
    "   ...:     def __setattr__(self, key, value):\n",
    "   ...:         print(f'{key}: {value}')\n",
    "   # ...:         self.key = value # 递归调用\n",
    "   ...:         #raise Exception(\"setattr\")\n",
    "   ...:         self[key]=value\n",
    "   ...:\n",
    "   ...:     def __getattr__(self, c):\n",
    "   ...:         return self.a + self.b\n",
    "   ...:     def __delattr__(self, key):\n",
    "   ...:         del  self.key\n",
    "   ...:         print(\"Removing {self}.{key}\")\n",
    "   ...:\n",
    "\n",
    "In [10]: c = C(1,2)\n",
    "a: 1\n",
    "b: 2\n",
    "\n",
    "In [11]: c.rr = 123\n",
    "rr: 123\n",
    "\n",
    "# In [12]: c.rr\n",
    "# ---------------------------------------------------------------------------\n",
    "# RecursionError                            Traceback (most recent call last)\n",
    "# <ipython-input-12-b4434f969e90> in <module>\n",
    "# ----> 1 c.rr\n",
    "\n",
    "# <ipython-input-9-1165151a289d> in __getattr__(self, c)\n",
    "#      10\n",
    "#      11     def __getattr__(self, c):\n",
    "# ---> 12         return self.a + self.b\n",
    "#      13     def __delattr__(self, key):\n",
    "#      14         del  self.key\n",
    "\n",
    "# ... last 1 frames repeated, from the frame below ...\n",
    "\n",
    "# <ipython-input-9-1165151a289d> in __getattr__(self, c)\n",
    "#      10\n",
    "#      11     def __getattr__(self, c):\n",
    "# ---> 12         return self.a + self.b\n",
    "#      13     def __delattr__(self, key):\n",
    "#      14         del  self.key\n",
    "\n",
    "# RecursionError: maximum recursion depth exceeded while calling a Python object\n",
    "\n",
    "# 将对__getattr__(name)的访问转换为对self[index]的访问\n",
    "# self[index]被实现为__getitem__(index)\n",
    "In [13]: c[\"rr\"]\n",
    "Out[13]: 123\n",
    "In [14]: c.__getitem__(\"rr\")\n",
    "Out[14]: 123"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'d'"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 特性的设计\n",
    "\n",
    "# __getattribute__()方法提供了对属性更底层的一些操作。\n",
    "# 默认的实现逻辑是先从内部的__dict__（或__slots__）中查找已有的属性。\n",
    "# 如果属性没有找到则调用__getattr__()函数。\n",
    "\n",
    "# __ getattribute __ ()函数不能包含任何self.name属性的访问，因为会导致无限递归。\n",
    "\n",
    "# 为了获得__getattribute__()方法中的属性值，必须显式调用object基类中的方法\n",
    "\"\"\"\n",
    "object.__getattribute__(self, name)\n",
    "\"\"\"\n",
    "\n",
    "# 通过使用__getattribute__()方法阻止对内部__dict__属性的访问来实现不可变\n",
    "class C:\n",
    "    def __init__(self, n:str, v:str):\n",
    "        self.n = n\n",
    "        self.v = v\n",
    "        pass\n",
    "    # def __setattr__(self, name, value):\n",
    "    #     print(f\"self.__dict__: {self.__dict__}\")\n",
    "    #     if name in self.__dict__:\n",
    "    #         raise AttributeError(\"Cannot set {name}\".format(name=name) )\n",
    "    #     raise AttributeError( \"'{__class__.__name__}' has noattribute'{name}'\".format( __class__= self.__class__, name= name ) )\n",
    "    def __getattribute__( self, name ):\n",
    "        if name.startswith('_'): raise AttributeError\n",
    "        return object.__getattribute__( self, name )\n",
    "d = C(\"d\",\"D\")\n",
    "d.n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 数据修饰符的设计\n",
    "\n",
    "\n",
    "class C:\n",
    "    def __init__(self, a, b):\n",
    "        self.a = a\n",
    "        self.b = b\n",
    "    def __set__(self, key, value):\n",
    "        exec(f\"self.{key} = {value}\")\n",
    "c = C(1,2)\n",
    "\n",
    "c.__set__(\"c\",3)\n",
    "c.c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('rate: 10.92680006993152 kph = 6.789598762345432 mph = 5.9 knots',\n",
       " 10.92680006993152,\n",
       " 6.789598762345432)"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对于不同的单位来说，每一个类级别的属性都是一个修饰符，在get和set函数中提供转换过程的实现\n",
    "class Unit:\n",
    "    conversion= 1.0\n",
    "    def __get__( self, instance, owner ):\n",
    "        return instance.kph * self.conversion\n",
    "    def __set__( self, instance, value ):\n",
    "        instance.kph= value / self.conversion\n",
    "\n",
    "class Knots( Unit ):\n",
    "    conversion= 0.5399568\n",
    "    \n",
    "class MPH( Unit ):\n",
    "    conversion= 0.62137119\n",
    "\n",
    "class KPH( Unit ):\n",
    "    def __get__( self, instance, owner ):\n",
    "        return instance._kph\n",
    "    def __set__( self, instance, value ):\n",
    "        instance._kph= value\n",
    "\n",
    "\n",
    "class Measurement:\n",
    "    kph= KPH()\n",
    "    knots= Knots()\n",
    "    mph= MPH()\n",
    "    def __init__( self, kph=None, mph=None, knots=None ):\n",
    "        if kph: self.kph= kph\n",
    "        elif mph: self.mph= mph\n",
    "        elif knots: self.knots= knots\n",
    "        else:\n",
    "            raise TypeError\n",
    "    def __str__( self ):\n",
    "        return \"rate: {0.kph} kph = {0.mph} mph = {0.knots} knots\".format(self)\n",
    "    \n",
    "m2 = Measurement( knots=5.9 )\n",
    "str(m2), m2.kph, m2.mph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [],
   "source": [
    "class P:\n",
    "    def __init__(self, a, b):\n",
    "        self.a = a\n",
    "        self.b = b\n",
    "        self.value = a + b\n",
    "    @property\n",
    "    def card(self):\n",
    "        return self.value\n",
    "    @card.setter\n",
    "    def card(self, a):\n",
    "        self.a = a\n",
    "    @card.deleter\n",
    "    def card(self, a):\n",
    "        del self.a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p = P(1,2)\n",
    "\n",
    "p.a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "0f91ad8382ec8cc5df0944367793869acc25d4038e592b86a3b3dccd17340df3"
  },
  "kernelspec": {
   "display_name": "Python 3.7.3 64-bit ('base': conda)",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
